home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / win / wgraph.c < prev    next >
C/C++ Source or Header  |  1993-09-15  |  41KB  |  1,494 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: wgraph.c%v 3.50.1.13 1993/08/19 03:21:26 woo Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - win/wgraph.c */
  6. /*
  7.  * Copyright (C) 1992   Maurice Castro, Russell Lang
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Maurice Castro
  25.  *   Russell Lang
  26.  * 
  27.  * Send your comments or suggestions to 
  28.  *  info-gnuplot@dartmouth.edu.
  29.  * This is a mailing list; to join it send a note to 
  30.  *  info-gnuplot-request@dartmouth.edu.  
  31.  * Send bug reports to
  32.  *  bug-gnuplot@dartmouth.edu.
  33.  */
  34.  
  35. #define STRICT
  36. #include <windows.h>
  37. #include <windowsx.h>
  38. #if WINVER >= 0x030a
  39. #include <commdlg.h>
  40. #endif
  41. #ifndef __MSC__
  42. #include <mem.h>
  43. #endif
  44. #include <string.h>
  45. #include "wgnuplib.h"
  46. #include "wresourc.h"
  47. #include "wcommon.h"
  48.  
  49. LRESULT CALLBACK _export WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  50. void ReadGraphIni(LPGW lpgw);
  51.  
  52. /* ================================== */
  53.  
  54. #define MAXSTR 255
  55.  
  56. #define WGDEFCOLOR 15
  57. COLORREF wginitcolor[WGDEFCOLOR] =  {
  58.     RGB(0,0,255),    /* blue */
  59.     RGB(0,255,0),    /* green */
  60.     RGB(255,0,0),    /* red */
  61.     RGB(255,0,255), /* magenta */
  62.     RGB(0,0,128),    /* dark blue */
  63.     RGB(128,0,0),    /* dark red */
  64.     RGB(0,128,128),    /* dark cyan */
  65.     RGB(0,0,0),    /* black */
  66.     RGB(128,128,128), /* grey */
  67.     RGB(0,128,64),    /* very dark cyan */
  68.     RGB(128,128,0), /* dark yellow */
  69.     RGB(128,0,128),    /* dark magenta */
  70.     RGB(192,192,192), /* light grey */
  71.     RGB(0,255,255),    /* cyan */
  72.     RGB(255,255,0),    /* yellow */
  73. };
  74. #define WGDEFSTYLE 5
  75. int wginitstyle[WGDEFSTYLE] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT};
  76.  
  77. /* ================================== */
  78.  
  79. /* destroy memory blocks holding graph operations */
  80. void
  81. DestroyBlocks(LPGW lpgw)
  82. {
  83.     struct GWOPBLK *this, *next;
  84.     struct GWOP FAR *gwop;
  85.     unsigned int i;
  86.  
  87.     this = lpgw->gwopblk_head;
  88.     while (this != NULL) {
  89.         next = this->next;
  90.         if (!this->gwop) {
  91.             this->gwop = (struct GWOP FAR *)GlobalLock(this->hblk);
  92.         }
  93.         if (this->gwop) {
  94.             /* free all text strings within this block */
  95.             gwop = this->gwop;
  96.             for (i=0; i<GWOPMAX; i++) {
  97.                 if (gwop->htext)
  98.                     LocalFree(gwop->htext);
  99.                 gwop++;
  100.             }
  101.         }
  102.         GlobalUnlock(this->hblk);
  103.         GlobalFree(this->hblk);
  104.         LocalFreePtr(this);
  105.         this = next;
  106.     }
  107.     lpgw->gwopblk_head = NULL;
  108.     lpgw->gwopblk_tail = NULL;
  109.     lpgw->nGWOP = 0;
  110. }
  111.         
  112.     
  113. /* add a new memory block for graph operations */
  114. /* returns TRUE if block allocated */
  115. BOOL 
  116. AddBlock(LPGW lpgw)
  117. {
  118. HGLOBAL hblk;
  119. struct GWOPBLK *next, *this;
  120.  
  121.     /* create new block */
  122.     next = (struct GWOPBLK *)LocalAllocPtr(LHND, sizeof(struct GWOPBLK) );
  123.     if (next == NULL)
  124.         return FALSE;
  125.     hblk = GlobalAlloc(GHND, GWOPMAX*sizeof(struct GWOP));
  126.     if (hblk == NULL)
  127.         return FALSE;
  128.     next->hblk = hblk;
  129.     next->gwop = (struct GWOP FAR *)NULL;
  130.     next->next = (struct GWOPBLK *)NULL;
  131.     next->used = 0;
  132.     
  133.     /* attach it to list */
  134.     this = lpgw->gwopblk_tail;
  135.     if (this == NULL) {
  136.         lpgw->gwopblk_head = next;
  137.     }
  138.     else {
  139.         this->next = next;
  140.         this->gwop = (struct GWOP FAR *)NULL;
  141.         GlobalUnlock(this->hblk);
  142.     }
  143.     lpgw->gwopblk_tail = next;
  144.     next->gwop = (struct GWOP FAR *)GlobalLock(next->hblk);
  145.     if (next->gwop == (struct GWOP FAR *)NULL)
  146.         return FALSE;
  147.         
  148.     return TRUE;
  149. }
  150.  
  151.  
  152. void WDPROC
  153. GraphOp(LPGW lpgw, WORD op, WORD x, WORD y, LPSTR str)
  154. {
  155.     struct GWOPBLK *this;
  156.     struct GWOP FAR *gwop;
  157.     char *npstr;
  158.     
  159.     this = lpgw->gwopblk_tail;
  160.     if ( (this==NULL) || (this->used >= GWOPMAX) ) {
  161.         /* not enough space so get new block */
  162.         if (!AddBlock(lpgw))
  163.             return;
  164.         this = lpgw->gwopblk_tail;
  165.     }
  166.     gwop = &this->gwop[this->used];
  167.     gwop->op = op;
  168.     gwop->x = x;
  169.     gwop->y = y;
  170.     gwop->htext = 0;
  171.     if (str) {
  172.         gwop->htext = LocalAlloc(LHND, _fstrlen(str)+1);
  173.         npstr = LocalLock(gwop->htext);
  174.         if (gwop->htext && (npstr != (char *)NULL))
  175.             lstrcpy(npstr, str);
  176.         LocalUnlock(gwop->htext);
  177.     }
  178.     this->used++;
  179.     lpgw->nGWOP++;
  180.     return;
  181. }
  182.  
  183. /* ================================== */
  184.  
  185. void WDPROC
  186. GraphInit(LPGW lpgw)
  187. {
  188.     HMENU sysmenu;
  189.     WNDCLASS wndclass;
  190.     char buf[80];
  191.  
  192.     if (!lpgw->hPrevInstance) {
  193.         wndclass.style = CS_HREDRAW | CS_VREDRAW;
  194.         wndclass.lpfnWndProc = WndGraphProc;
  195.         wndclass.cbClsExtra = 0;
  196.         wndclass.cbWndExtra = 2 * sizeof(void FAR *);
  197.         wndclass.hInstance = lpgw->hInstance;
  198.         wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  199.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  200.         wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
  201.         wndclass.lpszMenuName = NULL;
  202.         wndclass.lpszClassName = szGraphClass;
  203.         RegisterClass(&wndclass);
  204.     }
  205.  
  206.     ReadGraphIni(lpgw);
  207.  
  208.     lpgw->hWndGraph = CreateWindow(szGraphClass, lpgw->Title,
  209.         WS_OVERLAPPEDWINDOW,
  210.         lpgw->Origin.x, lpgw->Origin.y,
  211.         lpgw->Size.x, lpgw->Size.y,
  212.         NULL, NULL, lpgw->hInstance, lpgw);
  213.  
  214.     lpgw->hPopMenu = CreatePopupMenu();
  215.     AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->graphtotop ? MF_CHECKED : MF_UNCHECKED), 
  216.         M_GRAPH_TO_TOP, "Bring to &Top");
  217.     AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->color ? MF_CHECKED : MF_UNCHECKED), 
  218.         M_COLOR, "C&olor");
  219.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
  220. #if WINVER >= 0x030a
  221.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_BACKGROUND, "&Background...");
  222.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
  223.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_LINESTYLE, "&Line Styles...");
  224. #endif
  225.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_PRINT, "&Print...");
  226.     if (lpgw->IniFile != (LPSTR)NULL) {
  227.         wsprintf(buf,"&Update %s",lpgw->IniFile);
  228.         AppendMenu(lpgw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
  229.     }
  230.  
  231.     /* modify the system menu to have the new items we want */
  232.     sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
  233.     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  234.     AppendMenu(sysmenu, MF_POPUP, (UINT)lpgw->hPopMenu, "&Options");
  235.     AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
  236.  
  237.     ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  238. }
  239.  
  240. /* close a graph window */
  241. void WDPROC
  242. GraphClose(LPGW lpgw)
  243. {
  244.     /* close window */
  245.     if (lpgw->hWndGraph)
  246.         DestroyWindow(lpgw->hWndGraph);
  247.     TextMessage();
  248.     lpgw->hWndGraph = NULL;
  249.  
  250.     lpgw->locked = TRUE;
  251.     DestroyBlocks(lpgw);
  252.     lpgw->locked = FALSE;
  253.  
  254. }
  255.     
  256.  
  257. void WDPROC
  258. GraphStart(LPGW lpgw)
  259. {
  260.     lpgw->locked = TRUE;
  261.     DestroyBlocks(lpgw);
  262.     if ( !lpgw->hWndGraph || !IsWindow(lpgw->hWndGraph) )
  263.         GraphInit(lpgw);
  264.     if (IsIconic(lpgw->hWndGraph))
  265.         ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  266.     if (lpgw->graphtotop)
  267.         BringWindowToTop(lpgw->hWndGraph);
  268. }
  269.         
  270. void WDPROC
  271. GraphEnd(LPGW lpgw)
  272. {
  273. RECT rect;
  274.     GetClientRect(lpgw->hWndGraph, &rect);
  275.     InvalidateRect(lpgw->hWndGraph, (LPRECT) &rect, 1);
  276.     lpgw->locked = FALSE;
  277.     UpdateWindow(lpgw->hWndGraph);
  278. }
  279.  
  280. void WDPROC
  281. GraphPrint(LPGW lpgw)
  282. {
  283.     if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
  284.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_PRINT,0L);
  285. }
  286.  
  287. void WDPROC
  288. GraphRedraw(LPGW lpgw)
  289. {
  290.     if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
  291.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  292. }
  293. /* ================================== */
  294.  
  295. void
  296. StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle)
  297. {
  298.     LOGPEN FAR *plp;
  299.  
  300.     plp = &lpgw->colorpen[i];
  301.     plp->lopnColor = ref;
  302.     if (colorstyle < 0) {
  303.         plp->lopnWidth.x = -colorstyle;
  304.         plp->lopnStyle = 0;
  305.     }
  306.     else {
  307.         plp->lopnWidth.x = 1;
  308.         plp->lopnStyle = colorstyle % 5;
  309.     }
  310.     plp->lopnWidth.y = 0;
  311.  
  312.     plp = &lpgw->monopen[i];
  313.     plp->lopnColor = RGB(0,0,0);
  314.     if (monostyle < 0) {
  315.         plp->lopnWidth.x = -monostyle;
  316.             plp->lopnStyle = 0;
  317.     }
  318.     else {
  319.         plp->lopnWidth.x = 1;
  320.         plp->lopnStyle = monostyle % 5;
  321.     }
  322.     plp->lopnWidth.y = 0;
  323. }
  324.  
  325. void
  326. MakePens(LPGW lpgw, HDC hdc)
  327. {
  328.     int i;
  329.  
  330.     if ((GetDeviceCaps(hdc,NUMCOLORS) == 2) || !lpgw->color) {
  331.         /* Monochrome Device */
  332.         /* create border pens */
  333.         lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[0]);    /* border */
  334.         lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[1]);     /* axis */
  335.         /* create drawing pens */
  336.         for (i=0; i<WGNUMPENS; i++)
  337.         {
  338.             lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[i+2]);
  339.             }
  340.         /* find number of solid, unit width line styles */
  341.         for (i=0; i<WGNUMPENS && lpgw->monopen[i+2].lopnStyle==PS_SOLID
  342.             && lpgw->monopen[i+2].lopnWidth.x==1; i++) ;
  343.         lpgw->numsolid = i ? i : 1;    /* must be at least 1 */
  344.         lpgw->hbrush = CreateSolidBrush(RGB(255,255,255));
  345.     }
  346.     else {
  347.         /* Color Device */
  348.         /* create border pens */
  349.         lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[0]);    /* border */
  350.         lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]);     /* axis */
  351.         /* create drawing pens */
  352.         for (i=0; i<WGNUMPENS; i++)
  353.         {
  354.             lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[i+2]);
  355.             }
  356.         /* find number of solid, unit width line styles */
  357.         for (i=0; i<WGNUMPENS && lpgw->colorpen[i+2].lopnStyle==PS_SOLID
  358.             && lpgw->colorpen[i+2].lopnWidth.x==1; i++) ;
  359.         lpgw->numsolid = i ? i : 1;    /* must be at least 1 */
  360.         lpgw->hbrush = CreateSolidBrush(lpgw->background);
  361.     }
  362. }
  363.  
  364. void
  365. DestroyPens(LPGW lpgw)
  366. {
  367.     int i;
  368.  
  369.     DeleteBrush(lpgw->hbrush);
  370.     DeletePen(lpgw->hbpen);
  371.     DeletePen(lpgw->hapen);
  372.     for (i=0; i<WGNUMPENS; i++)
  373.         DeletePen(lpgw->hpen[i]);
  374. }
  375.  
  376. /* ================================== */
  377.  
  378. void
  379. MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc)
  380. {
  381.     LOGFONT lf;
  382.     HFONT hfontold;
  383.     TEXTMETRIC tm;
  384.     int result;
  385.     char FAR *p;
  386.     int cx, cy;
  387.  
  388.     lpgw->rotate = FALSE;
  389.     _fmemset(&lf, 0, sizeof(LOGFONT));
  390.     _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
  391.     lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  392.     lf.lfCharSet = DEFAULT_CHARSET;
  393.     if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
  394.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  395.         lf.lfItalic = TRUE;
  396.     }
  397.     if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
  398.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  399.         lf.lfWeight = FW_BOLD;
  400.     }
  401.  
  402.     if (lpgw->hfonth == 0) {
  403.         lpgw->hfonth = CreateFontIndirect((LOGFONT FAR *)&lf);
  404.     }
  405.  
  406.     if (lpgw->hfontv == 0) {
  407.         lf.lfEscapement = 900;
  408.         lf.lfOrientation = 900;
  409.         lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&lf);
  410.     }
  411.  
  412.     /* save text size */
  413.     hfontold = SelectFont(hdc, lpgw->hfonth);
  414. #ifdef WIN32
  415.     {
  416.     SIZE size;
  417.     GetTextExtentPoint(hdc,"0123456789",10, (LPSIZE)&size);
  418.     cx = size.cx;
  419.     cy = size.cy;
  420.     }
  421. #else
  422.     {
  423.     DWORD extent;
  424.     extent = GetTextExtent(hdc,"0123456789",10);
  425.     cx = LOWORD(extent);
  426.     cy = HIWORD(extent);
  427.     }
  428. #endif
  429.     lpgw->vchar = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
  430.     lpgw->hchar = MulDiv(cx/10,lpgw->xmax,lprect->right - lprect->left);
  431.     /* find out if we can rotate text 90deg */
  432.     SelectFont(hdc, lpgw->hfontv);
  433.     result = GetDeviceCaps(hdc, TEXTCAPS);
  434.     if ((result & TC_CR_90) || (result & TC_CR_ANY))
  435.         lpgw->rotate = 1;
  436.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  437.     if (tm.tmPitchAndFamily & TMPF_VECTOR)
  438.         lpgw->rotate = 1;    /* vector fonts can all be rotated */
  439. #if WINVER >=0x030a
  440.     if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
  441.         lpgw->rotate = 1;    /* truetype fonts can all be rotated */
  442. #endif
  443.     SelectFont(hdc, hfontold);
  444.     return;
  445. }
  446.  
  447. void
  448. DestroyFonts(LPGW lpgw)
  449. {
  450.     if (lpgw->hfonth) {
  451.         DeleteFont(lpgw->hfonth);
  452.         lpgw->hfonth = 0;
  453.     }
  454.     if (lpgw->hfontv) {
  455.         DeleteFont(lpgw->hfontv);
  456.         lpgw->hfontv = 0;
  457.     }
  458.     return;
  459. }
  460.  
  461. void
  462. SetFont(LPGW lpgw, HDC hdc)
  463. {
  464.     if (lpgw->rotate && lpgw->angle) {
  465.         if (lpgw->hfontv)
  466.             SelectFont(hdc, lpgw->hfontv);
  467.     }
  468.     else {
  469.         if (lpgw->hfonth)
  470.             SelectFont(hdc, lpgw->hfonth);
  471.     }
  472.     return;
  473. }
  474.  
  475. void
  476. SelFont(LPGW lpgw) {
  477. #if WINVER >= 0x030a
  478.     LOGFONT lf;
  479.     CHOOSEFONT cf;
  480.     HDC hdc;
  481.     char lpszStyle[LF_FACESIZE]; 
  482.     char FAR *p;
  483.  
  484.     /* Set all structure fields to zero. */
  485.     _fmemset(&cf, 0, sizeof(CHOOSEFONT));
  486.     _fmemset(&lf, 0, sizeof(LOGFONT));
  487.     cf.lStructSize = sizeof(CHOOSEFONT);
  488.     cf.hwndOwner = lpgw->hWndGraph;
  489.     _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
  490.     if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
  491.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  492.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  493.     }
  494.     else if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
  495.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  496.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  497.     }
  498.     else
  499.         _fstrcpy(lpszStyle,"Regular");
  500.     cf.lpszStyle = lpszStyle;
  501.     hdc = GetDC(lpgw->hWndGraph);
  502.     lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  503.     ReleaseDC(lpgw->hWndGraph, hdc);
  504.     cf.lpLogFont = &lf;
  505.     cf.nFontType = SCREEN_FONTTYPE;
  506.     cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
  507.     if (ChooseFont(&cf)) {
  508.         _fstrcpy(lpgw->fontname,lf.lfFaceName);
  509.         lpgw->fontsize = cf.iPointSize / 10;
  510.         if (cf.nFontType & BOLD_FONTTYPE)
  511.             lstrcat(lpgw->fontname," Bold");
  512.         if (cf.nFontType & ITALIC_FONTTYPE)
  513.             lstrcat(lpgw->fontname," Italic");
  514.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  515.     }
  516. #endif
  517. }
  518.  
  519. /* ================================== */
  520.  
  521. void
  522. drawgraph(LPGW lpgw, HDC hdc, LPRECT rect)
  523. {
  524.     int xdash, ydash;            /* the transformed coordinates */
  525.     int rr, rl, rt, rb;
  526.     struct GWOP FAR *curptr;
  527.     struct GWOPBLK *blkptr;
  528.     int htic, vtic, vshift;
  529.     unsigned int lastop=-1;        /* used for plotting last point on a line */
  530.     int pen, numsolid;
  531.     int polymax = 200;
  532.     int polyi = 0;
  533.     POINT *ppt;
  534.     unsigned int ngwop=0;
  535.     BOOL isColor;
  536.  
  537.     if (lpgw->locked) 
  538.         return;
  539.  
  540.      isColor= GetDeviceCaps(hdc, NUMCOLORS) > 2;
  541.     if (lpgw->background != RGB(255,255,255) && lpgw->color && isColor) {
  542.         SetBkColor(hdc,lpgw->background);
  543.         FillRect(hdc, rect, lpgw->hbrush);
  544.     }
  545.  
  546.     ppt = (POINT *)LocalAllocPtr(LHND, (polymax+1) * sizeof(POINT));
  547.  
  548.     rr = rect->right;
  549.     rl = rect->left;
  550.     rt = rect->top;
  551.     rb = rect->bottom;
  552.  
  553.     htic = MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
  554.     vtic = MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
  555.  
  556.     lpgw->angle = 0;
  557.     SetFont(lpgw, hdc);
  558.     SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
  559.     vshift = MulDiv(lpgw->vchar, rb-rt, lpgw->ymax)/2;
  560.  
  561.     pen = 0;
  562.     SelectPen(hdc, lpgw->hpen[pen]);
  563.     numsolid = lpgw->numsolid;
  564.  
  565.     /* do the drawing */
  566.     blkptr = lpgw->gwopblk_head;
  567.     curptr = NULL;
  568.     if (blkptr) {
  569.         if (!blkptr->gwop)
  570.             blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
  571.         if (!blkptr->gwop)
  572.             return;
  573.         curptr = (struct GWOP FAR *)blkptr->gwop;
  574.     }
  575.     while(ngwop < lpgw->nGWOP)
  576.        {
  577.         /* transform the coordinates */
  578.         xdash = MulDiv(curptr->x, rr-rl-1, lpgw->xmax) + rl;
  579.         ydash = MulDiv(curptr->y, rt-rb+1, lpgw->ymax) + rb - 1;
  580.         if ((lastop==W_vect) && (curptr->op!=W_vect)) {
  581.             if (polyi >= 2)
  582.                 Polyline(hdc, ppt, polyi);
  583.             polyi = 0;
  584.         }
  585.         switch (curptr->op) {
  586.             case 0:    /* have run past last in this block */
  587.                 break;
  588.             case W_move:
  589.                 ppt[0].x = xdash;
  590.                 ppt[0].y = ydash;
  591.                 polyi = 1;;
  592.                 break;
  593.             case W_vect:
  594.                 ppt[polyi].x = xdash;
  595.                 ppt[polyi].y = ydash;
  596.                 polyi++;
  597.                 if (polyi >= polymax) {
  598.                     Polyline(hdc, ppt, polyi);
  599.                     ppt[0].x = xdash;
  600.                     ppt[0].y = ydash;
  601.                     polyi = 1;;
  602.                 }
  603.                 break;
  604.             case W_line_type:
  605.                 switch (curptr->x)
  606.                 {
  607.                     case -2:        /* black 2 pixel wide */
  608.                         SelectPen(hdc, lpgw->hbpen);
  609.                         if (lpgw->color && isColor)
  610.                             SetTextColor(hdc, lpgw->colorpen[0].lopnColor);
  611.                         break;
  612.                     case -1:        /* black 1 pixel wide doted */
  613.                         SelectPen(hdc, lpgw->hapen);
  614.                         if (lpgw->color && isColor)
  615.                             SetTextColor(hdc, lpgw->colorpen[1].lopnColor);
  616.                         break;
  617.                     default:
  618.                         SelectPen(hdc, lpgw->hpen[(curptr->x)%WGNUMPENS]);
  619.                         if (lpgw->color && isColor)
  620.                             SetTextColor(hdc, lpgw->colorpen[(curptr->x)%WGNUMPENS + 2].lopnColor);
  621.                 }
  622.                 pen = curptr->x;
  623.                 break;
  624.             case W_put_text:
  625.                 {char *str;
  626.                 str = LocalLock(curptr->htext);
  627.                 if (str) {
  628.                     ydash += vshift;
  629.                     SetBkMode(hdc,TRANSPARENT);
  630.                     TextOut(hdc,xdash,ydash,str,lstrlen(str));
  631.                     SetBkMode(hdc,OPAQUE);
  632.                 }
  633.                 LocalUnlock(curptr->htext);
  634.                 }
  635.                 break;
  636.             case W_text_angle:
  637.                 lpgw->angle = curptr->x;
  638.                 SetFont(lpgw,hdc);
  639.                 break;
  640.             case W_justify:
  641.                 switch (curptr->x)
  642.                 {
  643.                     case LEFT:
  644.                         SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
  645.                         break;
  646.                     case RIGHT:
  647.                         SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
  648.                         break;
  649.                     case CENTRE:
  650.                         SetTextAlign(hdc, TA_CENTER|TA_BOTTOM);
  651.                         break;
  652.                     }
  653.                 break;
  654.             case W_dot:
  655.                 if (pen >= numsolid) {
  656.                     pen %= numsolid;    /* select solid pen */
  657.                     SelectPen(hdc, lpgw->hpen[pen]);
  658.                 }
  659.                 MoveTo(hdc,xdash,ydash);
  660.                 LineTo(hdc,xdash+1,ydash);
  661.                 break;
  662.             case W_diamond: /* do diamond */ 
  663.                 if (pen >= numsolid) {
  664.                     pen %= numsolid;
  665.                     SelectPen(hdc, lpgw->hpen[pen]);
  666.                 }
  667.                 MoveTo(hdc,xdash-htic,ydash);
  668.                 LineTo(hdc,xdash,ydash-vtic);
  669.                 LineTo(hdc,xdash+htic,ydash);
  670.                 LineTo(hdc,xdash,ydash+vtic);
  671.                 LineTo(hdc,xdash-htic,ydash);
  672.                 MoveTo(hdc,xdash,ydash);
  673.                 LineTo(hdc,xdash+1,ydash);
  674.                 break;
  675.             case W_plus: /* do plus */ 
  676.                 if (pen >= numsolid) {
  677.                     pen %= numsolid;
  678.                     SelectPen(hdc, lpgw->hpen[pen]);
  679.                 }
  680.                 MoveTo(hdc,xdash-htic,ydash);
  681.                 LineTo(hdc,xdash+htic+1,ydash);
  682.                 MoveTo(hdc,xdash,ydash-vtic);
  683.                 LineTo(hdc,xdash,ydash+vtic+1);
  684.                 break;
  685.             case W_box: /* do box */ 
  686.                 if (pen >= numsolid) {
  687.                     pen %= numsolid;
  688.                     SelectPen(hdc, lpgw->hpen[pen]);
  689.                 }
  690.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  691.                 LineTo(hdc,xdash+htic,ydash-vtic);
  692.                 LineTo(hdc,xdash+htic,ydash+vtic);
  693.                 LineTo(hdc,xdash-htic,ydash+vtic);
  694.                 LineTo(hdc,xdash-htic,ydash-vtic);
  695.                 MoveTo(hdc,xdash,ydash);
  696.                 LineTo(hdc,xdash+1,ydash);
  697.                 break;
  698.             case W_cross: /* do X */ 
  699.                 if (pen >= numsolid) {
  700.                     pen %= numsolid;
  701.                     SelectPen(hdc, lpgw->hpen[pen]);
  702.                 }
  703.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  704.                 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
  705.                 MoveTo(hdc,xdash-htic,ydash+vtic);
  706.                 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
  707.                 break;
  708.             case W_triangle: /* do triangle */ 
  709.                 if (pen >= numsolid) {
  710.                     pen %= numsolid;
  711.                     SelectPen(hdc, lpgw->hpen[pen]);
  712.                 }
  713.                 MoveTo(hdc,xdash,ydash-(4*vtic/3));
  714.                 LineTo(hdc,xdash-(4*htic/3),ydash+(2*vtic/3));
  715.                 LineTo(hdc,xdash+(4*htic/3),ydash+(2*vtic/3));
  716.                 LineTo(hdc,xdash,ydash-(4*vtic/3));
  717.                 MoveTo(hdc,xdash,ydash);
  718.                 LineTo(hdc,xdash+1,ydash);
  719.                 break;
  720.             case W_star: /* do star */ 
  721.                 if (pen >= numsolid) {
  722.                     pen %= numsolid;
  723.                     SelectPen(hdc, lpgw->hpen[pen]);
  724.                 }
  725.                 MoveTo(hdc,xdash-htic,ydash);
  726.                 LineTo(hdc,xdash+htic+1,ydash);
  727.                 MoveTo(hdc,xdash,ydash-vtic);
  728.                 LineTo(hdc,xdash,ydash+vtic+1);
  729.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  730.                 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
  731.                 MoveTo(hdc,xdash-htic,ydash+vtic);
  732.                 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
  733.                 break;
  734.         }
  735.         lastop = curptr->op;
  736.         ngwop++;
  737.         curptr++;
  738.         if ((unsigned)(curptr - blkptr->gwop) >= GWOPMAX) {
  739.             GlobalUnlock(blkptr->hblk);
  740.             blkptr->gwop = (struct GWOP FAR *)NULL;
  741.             blkptr = blkptr->next;
  742.             if (!blkptr->gwop)
  743.                 blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
  744.             if (!blkptr->gwop)
  745.                     return;
  746.                 curptr = (struct GWOP FAR *)blkptr->gwop;
  747.         }
  748.     }
  749.     if (polyi >= 2)
  750.         Polyline(hdc, ppt, polyi);
  751.     LocalFreePtr(ppt);
  752. }
  753.  
  754. /* ================================== */
  755.  
  756. /* copy graph window to clipboard */
  757. void
  758. CopyClip(LPGW lpgw)
  759. {
  760.     RECT rect;
  761.     HDC mem;
  762.     HBITMAP bitmap;
  763.     HANDLE hmf;
  764.     GLOBALHANDLE hGMem;
  765.     LPMETAFILEPICT lpMFP;
  766.     HWND hwnd;
  767.     HDC hdc;
  768.  
  769.     hwnd = lpgw->hWndGraph;
  770.  
  771.     /* view the window */
  772.     if (IsIconic(hwnd))
  773.         ShowWindow(hwnd, SW_SHOWNORMAL);
  774.     BringWindowToTop(hwnd);
  775.     UpdateWindow(hwnd);
  776.  
  777.     /* get the context */
  778.     hdc = GetDC(hwnd);
  779.     GetClientRect(hwnd, &rect);
  780.     /* make a bitmap and copy it there */
  781.     mem = CreateCompatibleDC(hdc);
  782.     bitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left,
  783.             rect.bottom - rect.top);
  784.     if (bitmap) {
  785.         /* there is enough memory and the bitmaps OK */
  786.         SelectBitmap(mem, bitmap);
  787.         BitBlt(mem,0,0,rect.right - rect.left, 
  788.             rect.bottom - rect.top, hdc, rect.left,
  789.             rect.top, SRCCOPY);
  790.     }
  791.     else {
  792.         MessageBeep(MB_ICONHAND);
  793.         MessageBox(hwnd, "Insufficient Memory to Copy Clipboard", 
  794.             lpgw->Title, MB_ICONHAND | MB_OK);
  795.     }
  796.     DeleteDC(mem);
  797.     ReleaseDC(hwnd, hdc);
  798.  
  799.     hdc = CreateMetaFile((LPSTR)NULL);
  800.     SetMapMode(hdc, MM_ANISOTROPIC);
  801. #ifdef WIN32
  802.     SetWindowExtEx(hdc, rect.right, rect.bottom, (LPSIZE)NULL);
  803. #else
  804.     SetWindowExt(hdc, rect.right, rect.bottom);
  805. #endif
  806.     drawgraph(lpgw, hdc, (void *) &rect);
  807.     hmf = CloseMetaFile(hdc);
  808.  
  809.     hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(METAFILEPICT));
  810.     lpMFP = (LPMETAFILEPICT) GlobalLock(hGMem);
  811.     hdc = GetDC(hwnd);    /* get window size */
  812.     GetClientRect(hwnd, &rect);
  813.     /* in MM_ANISOTROPIC, xExt & yExt give suggested size in 0.01mm units */
  814.     lpMFP->mm = MM_ANISOTROPIC;
  815.     lpMFP->xExt = MulDiv(rect.right-rect.left, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
  816.     lpMFP->yExt = MulDiv(rect.bottom-rect.top, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
  817.     lpMFP->hMF = hmf;
  818.     ReleaseDC(hwnd, hdc);
  819.     GlobalUnlock(hGMem);
  820.  
  821.     OpenClipboard(hwnd);
  822.     EmptyClipboard();
  823.     SetClipboardData(CF_METAFILEPICT,hGMem);
  824.     SetClipboardData(CF_BITMAP, bitmap);
  825.     CloseClipboard();
  826.     return;
  827. }
  828.  
  829. /* copy graph window to printer */
  830. void
  831. CopyPrint(LPGW lpgw)
  832. {
  833. #if WINVER >= 0x030a
  834.     HDC printer;
  835.     DLGPROC lpfnAbortProc;
  836.     DLGPROC lpfnPrintDlgProc;
  837.     PRINTDLG pd;
  838.     HWND hwnd;
  839.     RECT rect;
  840.     PRINT pr;
  841.     UINT widabort;
  842.  
  843.     hwnd = lpgw->hWndGraph;
  844.  
  845.     _fmemset(&pd, 0, sizeof(PRINTDLG));
  846.     pd.lStructSize = sizeof(PRINTDLG);
  847.     pd.hwndOwner = hwnd;
  848.     pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
  849.  
  850.     if (!PrintDlg(&pd))
  851.         return;
  852.     printer = pd.hDC;
  853.     if (NULL == printer)
  854.         return;    /* abort */
  855.  
  856.     if (!PrintSize(printer, hwnd, &rect)) {
  857.         DeleteDC(printer);
  858.         return; /* abort */
  859.     }
  860.  
  861.     pr.hdcPrn = printer;
  862.     SetWindowLong(hwnd, 4, (LONG)((LPPRINT)&pr));
  863.     PrintRegister((LPPRINT)&pr);
  864.  
  865.     EnableWindow(hwnd,FALSE);
  866.     pr.bUserAbort = FALSE;
  867. #ifdef __DLL__
  868.     lpfnPrintDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintDlgProc");
  869.     lpfnAbortProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintAbortProc");
  870. #else
  871.     lpfnPrintDlgProc = (DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, hdllInstance);
  872.     lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)PrintAbortProc, hdllInstance);
  873. #endif
  874.     pr.hDlgPrint = CreateDialogParam(hdllInstance,"PrintDlgBox",hwnd,lpfnPrintDlgProc,(LPARAM)lpgw->Title);
  875.     Escape(printer,SETABORTPROC,0,(LPSTR)lpfnAbortProc,NULL);  
  876.     if (Escape(printer, STARTDOC, lstrlen(lpgw->Title),lpgw->Title, NULL) > 0) {
  877.         SetMapMode(printer, MM_TEXT);
  878.         SetBkMode(printer,OPAQUE);
  879.         DestroyFonts(lpgw);
  880.         MakeFonts(lpgw, (RECT FAR *)&rect, printer);
  881.         DestroyPens(lpgw);    /* rebuild pens */
  882.         MakePens(lpgw, printer);
  883.         drawgraph(lpgw, printer, (void *) &rect);
  884.         if (Escape(printer,NEWFRAME,0,NULL,NULL) > 0)
  885.             Escape(printer,ENDDOC,0,NULL,NULL);
  886.     }
  887.     if (!pr.bUserAbort) {
  888.         EnableWindow(hwnd,TRUE);
  889.         DestroyWindow(pr.hDlgPrint);
  890.     }
  891. #ifndef __DLL__
  892.     FreeProcInstance((FARPROC)lpfnPrintDlgProc);
  893.     FreeProcInstance((FARPROC)lpfnAbortProc);
  894. #endif
  895.     DeleteDC(printer);
  896.     SetWindowLong(hwnd, 4, (LONG)(0L));
  897.     PrintUnregister((LPPRINT)&pr);
  898.     /* make certain that the screen pen set is restored */
  899.     SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  900. #endif
  901.     return;
  902. }
  903.  
  904. /* ================================== */
  905. /*  INI file stuff */
  906. void
  907. WriteGraphIni(LPGW lpgw)
  908. {
  909.     RECT rect;
  910.     int i;
  911.     char entry[32];
  912.     LPLOGPEN pc;
  913.     LPLOGPEN pm;
  914.     LPSTR file = lpgw->IniFile;
  915.     LPSTR section = lpgw->IniSection;
  916.     char profile[80];
  917.  
  918.     if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
  919.         return;
  920.     if (IsIconic(lpgw->hWndGraph))
  921.         ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  922.     GetWindowRect(lpgw->hWndGraph,&rect);
  923.     wsprintf(profile, "%d %d", rect.left, rect.top);
  924.     WritePrivateProfileString(section, "GraphOrigin", profile, file);
  925.     wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
  926.     WritePrivateProfileString(section, "GraphSize", profile, file);
  927.     wsprintf(profile, "%s,%d", lpgw->fontname, lpgw->fontsize);
  928.     WritePrivateProfileString(section, "GraphFont", profile, file);
  929.     wsprintf(profile, "%d", lpgw->color);
  930.     WritePrivateProfileString(section, "GraphColor", profile, file);
  931.     wsprintf(profile, "%d", lpgw->graphtotop);
  932.     WritePrivateProfileString(section, "GraphToTop", profile, file);
  933.     wsprintf(profile, "%d %d %d",GetRValue(lpgw->background),
  934.             GetGValue(lpgw->background), GetBValue(lpgw->background));
  935.     WritePrivateProfileString(section, "GraphBackground", profile, file);
  936.  
  937.     /* now save pens */
  938.     for (i=0; i<WGNUMPENS+2; i++) {
  939.         if (i==0)
  940.             _fstrcpy(entry,"Border");
  941.         else if (i==1)
  942.             _fstrcpy(entry,"Axis");
  943.         else
  944.              wsprintf(entry,"Line%d",i-1);
  945.         pc = &lpgw->colorpen[i];
  946.         pm = &lpgw->monopen[i];
  947.         wsprintf(profile, "%d %d %d %d %d",GetRValue(pc->lopnColor),
  948.             GetGValue(pc->lopnColor), GetBValue(pc->lopnColor),
  949.             (pc->lopnWidth.x != 1) ? -pc->lopnWidth.x : pc->lopnStyle, 
  950.             (pm->lopnWidth.x != 1) ? -pm->lopnWidth.x : pm->lopnStyle);
  951.         WritePrivateProfileString(section, entry, profile, file);
  952.     }
  953.     return;
  954. }
  955.  
  956. void
  957. ReadGraphIni(LPGW lpgw)
  958. {
  959.     LPSTR file = lpgw->IniFile;
  960.     LPSTR section = lpgw->IniSection;
  961.     char profile[81];
  962.     char entry[32];
  963.     LPSTR p;
  964.     int i,r,g,b,colorstyle,monostyle;
  965.     COLORREF ref;
  966.     BOOL bOKINI;
  967.  
  968.     bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
  969.     if (!bOKINI)
  970.         profile[0] = '\0';
  971.  
  972.     if (bOKINI)
  973.       GetPrivateProfileString(section, "GraphOrigin", "", profile, 80, file);
  974.     if ( (p = GetInt(profile, &lpgw->Origin.x)) == NULL)
  975.         lpgw->Origin.x = CW_USEDEFAULT;
  976.     if ( (p = GetInt(p, &lpgw->Origin.y)) == NULL)
  977.         lpgw->Origin.y = CW_USEDEFAULT;
  978.     if (bOKINI)
  979.       GetPrivateProfileString(section, "GraphSize", "", profile, 80, file);
  980.     if ( (p = GetInt(profile, &lpgw->Size.x)) == NULL)
  981.         lpgw->Size.x = CW_USEDEFAULT;
  982.     if ( (p = GetInt(p, &lpgw->Size.y)) == NULL)
  983.         lpgw->Size.y = CW_USEDEFAULT;
  984.  
  985.     if (bOKINI)
  986.       GetPrivateProfileString(section, "GraphFont", "", profile, 80, file);
  987.     {
  988.         char FAR *size;
  989.         size = _fstrchr(profile,',');
  990.         if (size) {
  991.             *size++ = '\0';
  992.             if ( (p = GetInt(size, &lpgw->fontsize)) == NULL)
  993.                 lpgw->fontsize = WINFONTSIZE;
  994.         }
  995.         _fstrcpy(lpgw->fontname, profile);
  996.         if (lpgw->fontsize == 0)
  997.             lpgw->fontsize = WINFONTSIZE;
  998.         if (!(*lpgw->fontname))
  999.             if (LOWORD(GetVersion()) == 3)
  1000.                 _fstrcpy(lpgw->fontname,WIN30FONT);
  1001.             else
  1002.                 _fstrcpy(lpgw->fontname,WINFONT);
  1003.     }
  1004.  
  1005.     if (bOKINI)
  1006.       GetPrivateProfileString(section, "GraphColor", "", profile, 80, file);
  1007.         if ( (p = GetInt(profile, &lpgw->color)) == NULL)
  1008.             lpgw->color = TRUE;
  1009.  
  1010.     if (bOKINI)
  1011.       GetPrivateProfileString(section, "GraphToTop", "", profile, 80, file);
  1012.         if ( (p = GetInt(profile, &lpgw->graphtotop)) == NULL)
  1013.             lpgw->graphtotop = TRUE;
  1014.  
  1015.     lpgw->background = RGB(255,255,255);
  1016.     if (bOKINI)
  1017.       GetPrivateProfileString(section, "GraphBackground", "", profile, 80, file);
  1018.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1019.          ((p = GetInt(p, &g)) != NULL) &&
  1020.          ((p = GetInt(p, &b)) != NULL) )
  1021.             lpgw->background = RGB(r,g,b);
  1022.  
  1023.     StorePen(lpgw, 0,RGB(0,0,0),PS_SOLID,PS_SOLID);
  1024.     if (bOKINI)
  1025.       GetPrivateProfileString(section, "Border", "", profile, 80, file);
  1026.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1027.          ((p = GetInt(p, &g)) != NULL) &&
  1028.          ((p = GetInt(p, &b)) != NULL) &&
  1029.          ((p = GetInt(p, &colorstyle)) != NULL) &&
  1030.          ((p = GetInt(p, &monostyle)) != NULL) )
  1031.             StorePen(lpgw,0,RGB(r,g,b),colorstyle,monostyle);
  1032.  
  1033.     StorePen(lpgw, 1,RGB(192,192,192),PS_DOT,PS_DOT);
  1034.     if (bOKINI)
  1035.       GetPrivateProfileString(section, "Axis", "", profile, 80, file);
  1036.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1037.          ((p = GetInt(p, &g)) != NULL) &&
  1038.          ((p = GetInt(p, &b)) != NULL) &&
  1039.          ((p = GetInt(p, &colorstyle)) != NULL) &&
  1040.          ((p = GetInt(p, &monostyle)) != NULL) )
  1041.             StorePen(lpgw,1,RGB(r,g,b),colorstyle,monostyle);
  1042.  
  1043.     for (i=0; i<WGNUMPENS; i++)
  1044.     {
  1045.         ref = wginitcolor[ i%WGDEFCOLOR ];
  1046.         colorstyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
  1047.         monostyle  = wginitstyle[ i%WGDEFSTYLE ];
  1048.         StorePen(lpgw, i+2,ref,colorstyle,monostyle);
  1049.         wsprintf(entry,"Line%d",i+1);
  1050.         if (bOKINI)
  1051.           GetPrivateProfileString(section, entry, "", profile, 80, file);
  1052.         if ( ((p = GetInt(profile, &r)) != NULL) &&
  1053.              ((p = GetInt(p, &g)) != NULL) &&
  1054.              ((p = GetInt(p, &b)) != NULL) &&
  1055.              ((p = GetInt(p, &colorstyle)) != NULL) &&
  1056.              ((p = GetInt(p, &monostyle)) != NULL) )
  1057.                 StorePen(lpgw,i+2,RGB(r,g,b),colorstyle,monostyle);
  1058.     }
  1059. }
  1060.  
  1061.  
  1062. /* ================================== */
  1063.  
  1064. #define LS_DEFLINE 2
  1065. typedef struct tagLS {
  1066.     int    widtype;
  1067.     int    wid;
  1068.     HWND    hwnd;
  1069.     int    pen;            /* current pen number */
  1070.     LOGPEN    colorpen[WGNUMPENS+2];    /* logical color pens */
  1071.     LOGPEN    monopen[WGNUMPENS+2];    /* logical mono pens */
  1072. } LS;
  1073. typedef LS FAR*  LPLS;
  1074.     
  1075.  
  1076. COLORREF
  1077. GetColor(HWND hwnd, COLORREF ref)
  1078. {
  1079. CHOOSECOLOR cc;
  1080. COLORREF aclrCust[16];
  1081. int i;
  1082.  
  1083.     for (i=0; i<16; i++) {
  1084.         aclrCust[i] = RGB(0,0,0);
  1085.     }
  1086.     _fmemset(&cc, 0, sizeof(CHOOSECOLOR));
  1087.     cc.lStructSize = sizeof(CHOOSECOLOR);
  1088.     cc.hwndOwner = hwnd;
  1089.     cc.lpCustColors = aclrCust;
  1090.     cc.rgbResult = ref;
  1091.     cc.Flags = CC_RGBINIT;
  1092.     if (ChooseColor(&cc))
  1093.         return cc.rgbResult;
  1094.     return ref;
  1095. }
  1096.  
  1097.  
  1098. /* force update of owner draw button */
  1099. void
  1100. UpdateColorSample(HWND hdlg)
  1101. {
  1102.     RECT rect;
  1103.     POINT ptul, ptlr;
  1104.     GetWindowRect( GetDlgItem(hdlg, LS_COLORSAMPLE), &rect);
  1105.     ptul.x = rect.left;
  1106.     ptul.y = rect.top;
  1107.     ptlr.x = rect.right;
  1108.     ptlr.y = rect.bottom;
  1109.     ScreenToClient(hdlg, &ptul);
  1110.     ScreenToClient(hdlg, &ptlr);
  1111.     rect.left   = ptul.x;
  1112.     rect.top    = ptul.y;
  1113.     rect.right  = ptlr.x;
  1114.     rect.bottom = ptlr.y;
  1115.     InvalidateRect(hdlg, &rect, TRUE);
  1116.     UpdateWindow(hdlg);
  1117. }
  1118.  
  1119. BOOL CALLBACK _export
  1120. LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
  1121. {
  1122.     char buf[16];
  1123.     LPLS lpls;
  1124.     int i;
  1125.     UINT pen;
  1126.     LPLOGPEN plpm, plpc;
  1127.     lpls = (LPLS)GetWindowLong(GetParent(hdlg), 4);
  1128.  
  1129.     switch (wmsg) {
  1130.         case WM_INITDIALOG:
  1131.             pen = 2;
  1132.             for (i=0; i<WGNUMPENS+2; i++) {
  1133.                 if (i==0)
  1134.                     _fstrcpy(buf,"Border");
  1135.                 else if (i==1)
  1136.                     _fstrcpy(buf,"Axis");
  1137.                 else
  1138.                      wsprintf(buf,"Line%d",i-1);
  1139.                 SendDlgItemMessage(hdlg, LS_LINENUM, LB_ADDSTRING, 0, 
  1140.                     (LPARAM)((LPSTR)buf));
  1141.             }
  1142.             SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
  1143.  
  1144.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1145.                 (LPARAM)((LPSTR)"Solid"));
  1146.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1147.                 (LPARAM)((LPSTR)"Dash"));
  1148.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1149.                 (LPARAM)((LPSTR)"Dot"));
  1150.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1151.                 (LPARAM)((LPSTR)"DashDot"));
  1152.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1153.                 (LPARAM)((LPSTR)"DashDotDot"));
  1154.  
  1155.             plpm = &lpls->monopen[pen];
  1156.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1157.                 plpm->lopnStyle, 0L);
  1158.             wsprintf(buf,"%d",plpm->lopnWidth.x);
  1159.             SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1160.  
  1161.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1162.                 (LPARAM)((LPSTR)"Solid"));
  1163.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1164.                 (LPARAM)((LPSTR)"Dash"));
  1165.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1166.                 (LPARAM)((LPSTR)"Dot"));
  1167.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1168.                 (LPARAM)((LPSTR)"DashDot"));
  1169.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1170.                 (LPARAM)((LPSTR)"DashDotDot"));
  1171.  
  1172.             plpc = &lpls->colorpen[pen];
  1173.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1174.                 plpc->lopnStyle, 0L);
  1175.             wsprintf(buf,"%d",plpc->lopnWidth.x);
  1176.             SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1177.  
  1178.             return TRUE;
  1179.         case WM_COMMAND:
  1180.             pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, 0, 0L);
  1181.             plpm = &lpls->monopen[pen];
  1182.             plpc = &lpls->colorpen[pen];
  1183.             switch (LOWORD(wparam)) {
  1184.                 case LS_LINENUM:
  1185.                     wsprintf(buf,"%d",plpm->lopnWidth.x);
  1186.                     SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1187.                     SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1188.                         plpm->lopnStyle, 0L);
  1189.                     wsprintf(buf,"%d",plpc->lopnWidth.x);
  1190.                     SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1191.                     SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1192.                         plpc->lopnStyle, 0L);
  1193.                     UpdateColorSample(hdlg);
  1194.                     return FALSE;
  1195.                 case LS_MONOSTYLE:
  1196.                     plpm->lopnStyle = 
  1197.                         (UINT)SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_GETCURSEL, 0, 0L);
  1198.                     if (plpm->lopnStyle != 0) {
  1199.                         plpm->lopnWidth.x = 1;
  1200.                         wsprintf(buf,"%d",plpm->lopnWidth.x);
  1201.                         SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1202.                     }
  1203.                     return FALSE;
  1204.                 case LS_MONOWIDTH:
  1205.                     GetDlgItemText(hdlg, LS_MONOWIDTH, buf, 15);
  1206.                     GetInt(buf, &plpm->lopnWidth.x);
  1207.                     if (plpm->lopnWidth.x != 1) {
  1208.                         plpm->lopnStyle = 0;
  1209.                         SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1210.                             plpm->lopnStyle, 0L);
  1211.                     }
  1212.                     return FALSE;
  1213.                 case LS_CHOOSECOLOR:
  1214.                     plpc->lopnColor = GetColor(hdlg, plpc->lopnColor);
  1215.                     UpdateColorSample(hdlg);
  1216.                     return FALSE;
  1217.                 case LS_COLORSTYLE:
  1218.                     plpc->lopnStyle = 
  1219.                         (UINT)SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_GETCURSEL, 0, 0L);
  1220.                     if (plpc->lopnStyle != 0) {
  1221.                         plpc->lopnWidth.x = 1;
  1222.                         wsprintf(buf,"%d",plpc->lopnWidth.x);
  1223.                         SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1224.                     }
  1225.                     return FALSE;
  1226.                 case LS_COLORWIDTH:
  1227.                     GetDlgItemText(hdlg, LS_COLORWIDTH, buf, 15);
  1228.                     GetInt(buf, &plpc->lopnWidth.x);
  1229.                     if (plpc->lopnWidth.x != 1) {
  1230.                         plpc->lopnStyle = 0;
  1231.                         SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1232.                             plpc->lopnStyle, 0L);
  1233.                     }
  1234.                     return FALSE;
  1235.                 case LS_DEFAULT:
  1236.                     plpm = lpls->monopen;
  1237.                     plpc = lpls->colorpen;
  1238.                     /* border */
  1239.                     plpc->lopnColor   = RGB(0,0,0);
  1240.                     plpc->lopnStyle   = PS_SOLID;
  1241.                     plpc->lopnWidth.x = 1;
  1242.                     plpm->lopnStyle   = PS_SOLID;
  1243.                     plpm->lopnWidth.x = 1;
  1244.                     plpc++; plpm++;
  1245.                     /* axis */
  1246.                     plpc->lopnColor   = RGB(192,192,192);
  1247.                     plpc->lopnStyle   = PS_DOT;
  1248.                     plpc->lopnWidth.x = 1;
  1249.                     plpm->lopnStyle   = PS_DOT;
  1250.                     plpm->lopnWidth.x = 1;
  1251.                     /* LineX */
  1252.                     for (i=0; i<WGNUMPENS; i++) {
  1253.                         plpc++; plpm++;
  1254.                         plpc->lopnColor   = wginitcolor[ i%WGDEFCOLOR ];
  1255.                         plpc->lopnStyle   = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
  1256.                         plpc->lopnWidth.x = 1;
  1257.                         plpm->lopnStyle   = wginitstyle[ i%WGDEFSTYLE ];
  1258.                         plpm->lopnWidth.x = 1;
  1259.                     }
  1260.                     /* update window */
  1261.                     plpm = &lpls->monopen[pen];
  1262.                     plpc = &lpls->colorpen[pen];
  1263.                     SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
  1264.                     wsprintf(buf,"%d",plpm->lopnWidth.x);
  1265.                     SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1266.                     SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1267.                         plpm->lopnStyle, 0L);
  1268.                     wsprintf(buf,"%d",plpc->lopnWidth.x);
  1269.                     SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1270.                     SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1271.                         plpc->lopnStyle, 0L);
  1272.                     UpdateColorSample(hdlg);
  1273.                     return FALSE;
  1274.                 case IDOK:
  1275.                     EndDialog(hdlg, IDOK);
  1276.                     return TRUE;
  1277.                 case IDCANCEL:
  1278.                     EndDialog(hdlg, IDCANCEL);
  1279.                     return TRUE;
  1280.             }
  1281.             break;
  1282.         case WM_DRAWITEM:
  1283.             {
  1284.             HBRUSH hBrush;
  1285.             LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lparam;
  1286.             pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  1287.             plpc = &lpls->colorpen[pen];
  1288.             hBrush = CreateSolidBrush(plpc->lopnColor);
  1289.             FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
  1290.             FrameRect(lpdis->hDC, &lpdis->rcItem, GetStockBrush(BLACK_BRUSH));
  1291.             DeleteBrush(hBrush);
  1292.             }
  1293.             return FALSE;
  1294.     }
  1295.     return FALSE;
  1296. }
  1297.  
  1298.  
  1299.  
  1300. /* GetWindowLong(hwnd, 4) must be available for use */
  1301. BOOL
  1302. LineStyle(LPGW lpgw)
  1303. {
  1304. DLGPROC lpfnLineStyleDlgProc ;
  1305. BOOL status = FALSE;
  1306. LS ls;
  1307.     
  1308.     SetWindowLong(lpgw->hWndGraph, 4, (LONG)((LPLS)&ls));
  1309.     _fmemcpy(&ls.colorpen, &lpgw->colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1310.     _fmemcpy(&ls.monopen, &lpgw->monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1311.  
  1312. #ifdef __DLL__
  1313.     lpfnLineStyleDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "LineStyleDlgProc");
  1314. #else
  1315.     lpfnLineStyleDlgProc = (DLGPROC)MakeProcInstance((FARPROC)LineStyleDlgProc, hdllInstance);
  1316. #endif
  1317.     if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, lpfnLineStyleDlgProc)
  1318.         == IDOK) {
  1319.         _fmemcpy(&lpgw->colorpen, &ls.colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1320.         _fmemcpy(&lpgw->monopen, &ls.monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1321.         status = TRUE;
  1322.     }
  1323. #ifndef __DLL__
  1324.     FreeProcInstance((FARPROC)lpfnLineStyleDlgProc);
  1325. #endif
  1326.     SetWindowLong(lpgw->hWndGraph, 4, (LONG)(0L));
  1327.     return status;
  1328. }
  1329.  
  1330. /* ================================== */
  1331.  
  1332. LRESULT CALLBACK _export
  1333. WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1334. {
  1335.     HDC hdc;
  1336.     PAINTSTRUCT ps;
  1337.     RECT rect;
  1338.     LPGW lpgw;
  1339.  
  1340.     lpgw = (LPGW)GetWindowLong(hwnd, 0);
  1341.  
  1342.     switch(message)
  1343.     {
  1344.         case WM_SYSCOMMAND:
  1345.             switch(LOWORD(wParam))
  1346.             {
  1347.                 case M_GRAPH_TO_TOP:
  1348.                 case M_COLOR:
  1349.                 case M_CHOOSE_FONT:
  1350.                 case M_COPY_CLIP:
  1351.                 case M_LINESTYLE:
  1352.                 case M_PRINT:
  1353.                 case M_WRITEINI:
  1354.                 case M_REBUILDTOOLS:
  1355.                     SendMessage(hwnd, WM_COMMAND, wParam, lParam);
  1356.                     break;
  1357.                 case M_ABOUT:
  1358.                     if (lpgw->lptw)
  1359.                         AboutBox(hwnd,lpgw->lptw->AboutText);
  1360.                     return 0;
  1361.             }
  1362.             break;
  1363.         case WM_COMMAND:
  1364.             switch(LOWORD(wParam))
  1365.             {
  1366.                 case M_GRAPH_TO_TOP:
  1367.                     lpgw->graphtotop = !lpgw->graphtotop;
  1368.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1369.                     return(0);
  1370.                 case M_COLOR:
  1371.                     lpgw->color = !lpgw->color;
  1372.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1373.                     return(0);
  1374.                 case M_CHOOSE_FONT:
  1375.                     SelFont(lpgw);
  1376.                     return 0;
  1377.                 case M_COPY_CLIP:
  1378.                     CopyClip(lpgw);
  1379.                     return 0;
  1380.                 case M_LINESTYLE:
  1381.                     if (LineStyle(lpgw))
  1382.                         SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1383.                     return 0;
  1384.                 case M_BACKGROUND:
  1385.                     lpgw->background = GetColor(hwnd, lpgw->background);
  1386.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1387.                     return 0;
  1388.                 case M_PRINT:
  1389.                     CopyPrint(lpgw);
  1390.                     return 0;
  1391.                 case M_WRITEINI:
  1392.                     WriteGraphIni(lpgw);
  1393.                     if (lpgw->lptw)
  1394.                         WriteTextIni(lpgw->lptw);
  1395.                     return 0;
  1396.                 case M_REBUILDTOOLS:
  1397.                     lpgw->resized = TRUE;
  1398.                     if (lpgw->color) 
  1399.                         CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_CHECKED);
  1400.                     else
  1401.                         CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_UNCHECKED);
  1402.                     if (lpgw->graphtotop) 
  1403.                         CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_CHECKED);
  1404.                     else
  1405.                         CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_UNCHECKED);
  1406.                     DestroyPens(lpgw);
  1407.                     DestroyFonts(lpgw);
  1408.                     hdc = GetDC(hwnd);
  1409.                     MakePens(lpgw, hdc);
  1410.                     GetClientRect(hwnd, &rect);
  1411.                     MakeFonts(lpgw, (LPRECT)&rect, hdc);
  1412.                     ReleaseDC(hwnd, hdc);
  1413.                     GetClientRect(hwnd, &rect);
  1414.                     InvalidateRect(hwnd, (LPRECT) &rect, 1);
  1415.                     UpdateWindow(hwnd);
  1416.                     return 0;
  1417.             }
  1418.             return 0;
  1419.         case WM_RBUTTONDOWN:
  1420.             {
  1421.             POINT pt;
  1422.             pt.x = LOWORD(lParam);
  1423.             pt.y = HIWORD(lParam);
  1424.             ClientToScreen(hwnd,&pt);
  1425.             TrackPopupMenu(lpgw->hPopMenu, TPM_LEFTALIGN, 
  1426.                 pt.x, pt.y, 0, hwnd, NULL);
  1427.             }
  1428.             return(0);
  1429.         case WM_CREATE:
  1430.             lpgw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
  1431.             SetWindowLong(hwnd, 0, (LONG)lpgw);
  1432.             lpgw->hWndGraph = hwnd;
  1433.             hdc = GetDC(hwnd);
  1434.             MakePens(lpgw, hdc);
  1435.             GetClientRect(hwnd, &rect);
  1436.             MakeFonts(lpgw, (LPRECT)&rect, hdc);
  1437.             ReleaseDC(hwnd, hdc);
  1438. #if WINVER >= 0x030a
  1439.             {
  1440.             WORD version = LOWORD(GetVersion());
  1441.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1442.                 if ( lpgw->lptw && (lpgw->lptw->DragPre!=(LPSTR)NULL) && (lpgw->lptw->DragPost!=(LPSTR)NULL) )
  1443.                     DragAcceptFiles(hwnd, TRUE);
  1444.             }
  1445. #endif
  1446.             return(0);
  1447.         case WM_PAINT:
  1448.             hdc = BeginPaint(hwnd, &ps);
  1449.             SetMapMode(hdc, MM_TEXT);
  1450.             SetBkMode(hdc,OPAQUE);
  1451.             GetClientRect(hwnd, &rect);
  1452.             SetViewportExt(hdc, rect.right, rect.bottom);
  1453.             drawgraph(lpgw, hdc, (void *) &rect);
  1454.             EndPaint(hwnd, &ps);
  1455.             return 0;
  1456.         case WM_SIZE:
  1457.             /* update font sizes if graph resized */
  1458.             if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
  1459.                 RECT rect;
  1460.                 SendMessage(hwnd,WM_SYSCOMMAND,M_REBUILDTOOLS,0L);
  1461.                 GetWindowRect(hwnd,&rect);
  1462.                 lpgw->Size.x = rect.right-rect.left;
  1463.                 lpgw->Size.y = rect.bottom-rect.top;
  1464.             }
  1465.             break;
  1466. #if WINVER >= 0x030a
  1467.         case WM_DROPFILES:
  1468.             {
  1469.             WORD version = LOWORD(GetVersion());
  1470.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1471.                 if (lpgw->lptw)
  1472.                     DragFunc(lpgw->lptw, (HDROP)wParam);
  1473.             }
  1474.             break;
  1475. #endif
  1476.         case WM_DESTROY:
  1477.             DestroyPens(lpgw);
  1478.             DestroyFonts(lpgw);
  1479. #if __TURBOC__ >= 0x410    /* Borland C++ 3.1 or later */
  1480.             {
  1481.             WORD version = LOWORD(GetVersion());
  1482.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1483.                 DragAcceptFiles(hwnd, FALSE);
  1484.             }
  1485. #endif
  1486.             return 0;
  1487.         case WM_CLOSE:
  1488.             GraphClose(lpgw);
  1489.             return 0;
  1490.         }
  1491.     return DefWindowProc(hwnd, message, wParam, lParam);
  1492. }
  1493.  
  1494.